package org.dromara.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.dromara.admin.domain.*;
import org.dromara.admin.domain.vo.OrderVo;
import org.dromara.admin.domain.vo.UserDetailVo;
import org.dromara.admin.enums.AuditStatus;
import org.dromara.admin.enums.BillStatus;
import org.dromara.admin.enums.BillType;
import org.dromara.admin.service.IAdvancePayRecordService;
import org.dromara.admin.service.IContractBillService;
import org.dromara.admin.service.IUserDetailService;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.lessor.domain.House;
import org.dromara.system.domain.SysUser;
import org.springframework.stereotype.Service;
import org.dromara.admin.domain.bo.AdvanceBillBo;
import org.dromara.admin.domain.vo.AdvanceBillVo;
import org.dromara.admin.mapper.AdvanceBillMapper;
import org.dromara.admin.service.IAdvanceBillService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Collection;

import static com.baomidou.mybatisplus.extension.toolkit.Db.updateById;

/**
 * 垫资账单信息Service业务层处理
 *
 * @author Lion Li
 * @date 2025-09-05
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AdvanceBillServiceImpl implements IAdvanceBillService {

    private final AdvanceBillMapper baseMapper;
    private final IContractBillService contractBillService;
    private final IAdvancePayRecordService advancePayRecordService;
    private final IUserDetailService userDetailService;

    /**
     * 查询垫资账单信息
     *
     * @param id 主键
     * @return 垫资账单信息
     */
    @Override
    public AdvanceBillVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询垫资账单信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 垫资账单信息分页列表
     */
    @Override
    public TableDataInfo<AdvanceBillVo> queryPageList(AdvanceBillBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<AdvanceBill> lqw = buildQueryWrapper(bo);
        Page<AdvanceBillVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 资方获取自己的垫资账单信息列表
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return
     */
    @Override
    public TableDataInfo<AdvanceBillVo> queryPageMyList(AdvanceBillBo bo, PageQuery pageQuery) {
        MPJLambdaWrapper<AdvanceBill> wrapper = getAdvanceBillByJoinTable(bo)
            .eq(AdvanceBill::getCapitalUserId, bo.getCapitalUserId());
        Page<AdvanceBillVo> result = baseMapper.selectJoinPage(pageQuery.build(), AdvanceBillVo.class, wrapper);
        return TableDataInfo.build(result);
    }

    /**
     * 联表查询AdvanceBill表、order、AdvancePayRecord、SysUser表
     * @param bo
     * @return
     */
    private static MPJLambdaWrapper<AdvanceBill> getAdvanceBillByJoinTable(AdvanceBillBo bo) {
        // 使用MPJBaseMapper进行联表查询AdvanceBill表、order、AdvancePayRecord、SysUser表
        MPJLambdaWrapper<AdvanceBill> wrapper = new MPJLambdaWrapper<AdvanceBill>()
            .selectAll(AdvanceBill.class)
            .selectAssociation(Order.class, AdvanceBillVo::getOrder)
            .selectAssociation(AdvancePayRecord.class, AdvanceBillVo::getAdvancePayRecord)
            .selectAssociation("tu", SysUser.class, AdvanceBillVo::getTenantUser)
            .selectAssociation("lu", SysUser.class, AdvanceBillVo::getLessorUser)
            .selectAssociation("cu", SysUser.class, AdvanceBillVo::getCapitalUser)
            .selectAssociation("ld", UserDetail.class, AdvanceBillVo::getLessorUserDetail)
            .leftJoin(Order.class, Order::getId, AdvanceBill::getOrderId)
            .leftJoin(AdvancePayRecord.class, AdvancePayRecord::getBillId, AdvanceBill::getId)
            // 租客信息 join
            .leftJoin(SysUser.class, "tu", on -> on.eq(SysUser::getUserId, AdvanceBill::getUserId))
            // 出租方信息 join
            .leftJoin(SysUser.class, "lu", on -> on.eq(SysUser::getUserId, AdvanceBill::getLessorUserId))
            // 资方代理信息 join
            .leftJoin(SysUser.class, "cu", on -> on.eq(SysUser::getUserId, AdvanceBill::getCapitalUserId))
            // 出租方详细信息 join
            .leftJoin(UserDetail.class, "ld", on -> on.eq(UserDetail::getUserId, AdvanceBill::getLessorUserId))
            .like(StrUtil.isNotBlank(bo.getUserName()), "tu.user_name", bo.getUserName())
            .like(StrUtil.isNotBlank(bo.getLessorUserName()), "lu.user_name", bo.getLessorUserName())
            .like(StrUtil.isNotBlank(bo.getCapitalUserName()), "cu.user_name", bo.getCapitalUserName())
            .eq(StrUtil.isNotBlank(bo.getBillType()), AdvanceBill::getBillType, bo.getBillType())
            .eq(StrUtil.isNotBlank(bo.getAuditStatus()), AdvanceBill::getAuditStatus, bo.getAuditStatus());
        return wrapper;
    }

    /**
     * 查询符合条件的垫资账单信息列表
     *
     * @param bo 查询条件
     * @return 垫资账单信息列表
     */
    @Override
    public List<AdvanceBillVo> queryList(AdvanceBillBo bo) {
        LambdaQueryWrapper<AdvanceBill> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<AdvanceBill> buildQueryWrapper(AdvanceBillBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<AdvanceBill> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(AdvanceBill::getId);
        lqw.eq(StringUtils.isNotBlank(bo.getBillType()), AdvanceBill::getBillType, bo.getBillType());
        lqw.eq(bo.getBillAmount() != null, AdvanceBill::getBillAmount, bo.getBillAmount());
        lqw.eq(bo.getAmountReceivable() != null, AdvanceBill::getAmountReceivable, bo.getAmountReceivable());
        lqw.eq(bo.getAmountDiscount() != null, AdvanceBill::getAmountDiscount, bo.getAmountDiscount());
        lqw.eq(bo.getAmountReality() != null, AdvanceBill::getAmountReality, bo.getAmountReality());
        lqw.eq(bo.getAmountReceived() != null, AdvanceBill::getAmountReceived, bo.getAmountReceived());
        lqw.eq(StringUtils.isNotBlank(bo.getBillStatus()), AdvanceBill::getBillStatus, bo.getBillStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getAuditStatus()), AdvanceBill::getAuditStatus, bo.getAuditStatus());
        lqw.eq(bo.getPayTime() != null, AdvanceBill::getPayTime, bo.getPayTime());
        lqw.eq(bo.getExpiresTime() != null, AdvanceBill::getExpiresTime, bo.getExpiresTime());
        lqw.eq(StringUtils.isNotBlank(bo.getOverdue()), AdvanceBill::getOverdue, bo.getOverdue());
        lqw.eq(bo.getOrderId() != null, AdvanceBill::getOrderId, bo.getOrderId());
        lqw.eq(bo.getUserId() != null, AdvanceBill::getUserId, bo.getUserId());
        lqw.eq(bo.getLessorUserId() != null, AdvanceBill::getLessorUserId, bo.getLessorUserId());
        lqw.eq(bo.getCapitalUserId() != null, AdvanceBill::getCapitalUserId, bo.getCapitalUserId());
        lqw.eq(StringUtils.isNotBlank(bo.getRemarks()), AdvanceBill::getRemarks, bo.getRemarks());
        return lqw;
    }

    /**
     * 新增垫资账单信息
     *
     * @param bo 垫资账单信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(AdvanceBillBo bo) {
        AdvanceBill add = MapstructUtils.convert(bo, AdvanceBill.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改垫资账单信息
     *
     * @param bo 垫资账单信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(AdvanceBillBo bo) {
        AdvanceBill update = MapstructUtils.convert(bo, AdvanceBill.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(AdvanceBill entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除垫资账单信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 资方同意后创建垫资账单
     *
     * @param order 订单信息
     * @return 是否创建成功
     */
    @Override
    public Boolean createAdvanceBill(Order order) {
        // 根据订单时长除以6，创建多少个垫资账单
        long count = order.getContractMonth() / 6; // 计算有几个垫资账单
        // 获取当前用户的折扣比例
        UserDetailVo userDetailVo = userDetailService.queryById(order.getCapitalUserId());
        Long discountRate = userDetailVo.getDiscountRate(); // 折扣比例:98
        if (discountRate == null){
            throw new ServiceException("未设置资方折扣比例！");
        }
        // 计算折扣后每一期的金额
        BigDecimal amount = order.getRentTotal().multiply(new BigDecimal(discountRate)).divide(new BigDecimal(count * 100), 2, RoundingMode.HALF_UP);
        for (int i = 0; i < count; i++) {
            AdvanceBill advanceBill = new AdvanceBill();
            advanceBill.setIssueNumber(i + 1);
            advanceBill.setBillType(BillType.ADVANCE.getCode());
            advanceBill.setBillAmount(amount);
            advanceBill.setAmountReceivable(amount);
            advanceBill.setAmountDiscount(BigDecimal.ZERO);
            advanceBill.setAmountReality(BigDecimal.ZERO);
            advanceBill.setAmountReceived(BigDecimal.ZERO);
            advanceBill.setBillStatus(BillStatus.UNPAID.getCode());
//            advanceBill.setAuditStatus(AuditStatus.PENDING.getCode());
//            advanceBill.setExpiresTime(DateUtil.offsetMonth(order.getStartDate(), (i + 1) * 6));
            advanceBill.setOrderId(order.getId());
            advanceBill.setUserId(order.getUserId());
            advanceBill.setLessorUserId(order.getLessorUserId());
            advanceBill.setCapitalUserId(order.getCapitalUserId());
            boolean b = baseMapper.insert(advanceBill) > 0;
            if (!b) {
                throw new ServiceException("创建垫资账单过程失败!");
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 资方通过资方账单进行垫资支付
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean capitalPay(AdvanceBillBo bo) {
        // 查询数据库数据
        AdvanceBill advanceBill = baseMapper.selectById(bo.getId());
        if (BeanUtil.isEmpty(advanceBill)) {
            throw new ServiceException("未找到该笔垫资账单!");
        }
        if (!advanceBill.getCapitalUserId().equals(LoginHelper.getUserId())){
            throw new ServiceException("当前垫资账单非该资方的！");
        }
        // 获取账单状态是否已经付款-不是未付款状态
        if (!advanceBill.getBillStatus().equals(BillStatus.UNPAID.getCode())) {
            throw new ServiceException("该笔垫资账单已经付款过了或者坏账!");
        }

        // 创建垫资付款记录表
        bo.setAmountReality(advanceBill.getBillAmount());
        bo.setOrderId(advanceBill.getOrderId());
        bo.setCapitalUserId(advanceBill.getCapitalUserId());
        bo.setLessorUserId(advanceBill.getLessorUserId());
        advancePayRecordService.creatByAdvanceBillBo(bo);

        // 修改垫资账单表状态
        advanceBill.setAmountReality(advanceBill.getBillAmount());
        advanceBill.setAmountReceived(advanceBill.getBillAmount());
        advanceBill.setBillStatus(BillStatus.BILL_PAID.getCode());
        advanceBill.setAuditStatus(AuditStatus.PENDING.getCode());
        advanceBill.setPayTime(new Date());
        boolean b = baseMapper.updateById(advanceBill) > 0;
        if (!b) {
            throw new ServiceException("更新垫资账单信息状态异常！");
        }
        return Boolean.TRUE;
    }

    /**
     * 出租方审核付款记录后更新
     *
     * @param advanceBillVo
     * @return
     */
    @Override
    public Boolean reviewUpdate(AdvanceBillVo advanceBillVo) {
        AdvanceBill advanceBill = baseMapper.selectById(advanceBillVo.getId());
        if (BeanUtil.isEmpty(advanceBill)) {
            throw new ServiceException("未找到该笔垫资账单信息!");
        }
        advanceBill.setAuditStatus(advanceBillVo.getAuditStatus());
        advanceBill.setBillStatus(advanceBillVo.getBillStatus());
        advanceBill.setRemarks(advanceBillVo.getRemarks());
        boolean b = baseMapper.updateById(advanceBill) > 0;
        if (!b) {
            throw new ServiceException("更新垫资账单状态异常！");
        }
        return Boolean.TRUE;
    }
}
